package ppa.marc.importer.database;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import org.springframework.dao.DuplicateKeyException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;

import ppa.marc.domain.Field;
import ppa.marc.domain.Record;
import ppa.marc.importer.data.DataIntegrityException;
import ppa.marc.importer.data.RecordIdentityExtractor;

public class JdbcRecordInserter implements RecordInserter {
	private static final String INSERT_SQL = "insert into marc_record (marc_id) values (?)";
	private static final String SELECT_ID_SQL = "select id from marc_record where marc_id like ?";
	
	private final RecordIdentityExtractor recordIdentityExtractor;
	private final JdbcTemplate jdbcTemplate;
	private final FieldInserter fieldInserter;

	public JdbcRecordInserter(JdbcTemplate jdbcTemplate, RecordIdentityExtractor recordIdentityExtractor, FieldInserter fieldInserter) {
		this.jdbcTemplate = jdbcTemplate;
		this.recordIdentityExtractor = recordIdentityExtractor;
		this.fieldInserter = fieldInserter;
	}

	@Override
	public long insertRecord(Record record) throws DataInsertionException {
		long id;
		String unimardId = null;
		try {
			unimardId = recordIdentityExtractor.extractIdentityFrom(record);
			jdbcTemplate.update(createInsertStatementCreator(unimardId));
			id = jdbcTemplate.queryForInt(SELECT_ID_SQL, unimardId);
			insertFields(record, id);
		} catch (DataIntegrityException e) {
			throw new DataInsertionException(e.getMessage());
		} catch(DuplicateKeyException recordAlreadyExists) {
			throw new DataInsertionException("Record with identifier " + unimardId + " already exists.");
		}
		return id;
	}

	private void insertFields(Record record, long id) throws DataIntegrityException, DataInsertionException {
		int position = 0;
		for(Field field : record.getFields()) {
			fieldInserter.insertField(field, id, position++);
		}
	}

	private PreparedStatementCreator createInsertStatementCreator(final String unimardId) {
		return new PreparedStatementCreator() {
			public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
				PreparedStatement preparedStatement = connection.prepareStatement(INSERT_SQL);
				preparedStatement.setString(1, unimardId);
				return preparedStatement; 
			}
		};
	}
}
